#include "ChartView.h"

#include <QMessageBox>
#include<algorithm>
extern QList<QPointF> PointCould;

extern QList<QList<QVariant>> ret;//将Qvariant转换为QList<QList<QVariant>>
extern QList<QString> m_pItem;   //下拉框数据  表头

extern int TABLE_COL ; //表格列
extern int TABLE_ROW; //表格行

#define   CZ     5;  //坐标插值

CChartView::CChartView(QWidget *parent) : QWidget(parent)
{
    a_x = b_y =0;
//    m_valueLabel = nullptr;
    createChart();
    setupUi();

    m_valueLabel = new QLabel(this);
    m_valueLabel->setStyleSheet(QString("QLabel{color:#1564FF; font-family:\"Microsoft Yahei\"; font-size:12px; font-weight:bold;"
                                        " text-align:center;}"));
    m_valueLabel->setFixedSize(100, 24);
    m_valueLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    m_valueLabel->hide();

    connect(m_pHuaTu,SIGNAL(clicked(bool)),this,SLOT(slot_drawPointCloud()));
    connect(m_pNiHe,SIGNAL(clicked(bool)),this,SLOT(slot_drawNiheLine()));
    connect(m_pXuce,SIGNAL(clicked(bool)),this,SLOT(slot_drawShowTest()));
    connect(m_pCom[0],SIGNAL(currentIndexChanged(int )),this,SLOT(slot_changeLable()));
    connect(m_pCom[1],SIGNAL(currentIndexChanged(int )),this,SLOT(slot_changeLable()));

}

void CChartView::setupUi()
{
    m_Yuce = new QLabel();
    m_Yuce->setStyleSheet( "font-family:'幼圆';font-size:20px;");
    m_Yuce->setStyleSheet(QString("QLabel{color:#1564FF; font-family:\"Microsoft Yahei\"; font-size:25px; font-weight:bold;"
                                        " text-align:center;}"));


    m_pMylay = new QVBoxLayout(this);
    m_pMybar1 = new QToolBar();
    m_pMybar2 = new QToolBar();
    m_pMybar3 = new QToolBar();


    for (int i =0;i<8;i++)
    {
        m_pLab[i] =new QLabel();
    }
    m_pCom[0] = new QComboBox();
    m_pCom[1] = new QComboBox();
    m_pHuaTu = new QPushButton("画散点图");
    //"border:2px groove gray;border-radius:5px;padding:2px 4px;"
    m_pHuaTu->setStyleSheet("font-family:'幼圆';font-size:20px;"
                            "background-color: rgb(255, 255, 255);"
                            "color:#43CD80;"
                            "border-color:#43CD80;");
    m_pNiHe = new QPushButton("拟合生成");
    m_pNiHe->setStyleSheet("font-family:'幼圆';font-size:20px;"
                            "background-color: rgb(255, 255, 255);"
                           "color:#43CD80;"
                           "border-color:#43CD80;");

    m_pXuce = new QPushButton("开始预测");
    m_pXuce->setStyleSheet("background-color:#43CD80;color:rgb(255, 255, 255);"
                           "border-color:#43CD80;");
    m_pXuce->setFixedWidth(/*this->width()/4*/150);


    m_pStudy = new QPushButton("开始机器学习");
    m_pStudy->setStyleSheet("background-color:#43CD80;color:rgb(255, 255, 255);"
                            "border-color:#43CD80;");

    m_pLin = new QLineEdit();
    m_pLin->setFixedWidth(/*this->width()/4*/200);

    //设置字号
    QFont ft;
    ft.setPointSize(12);
    //设置颜色
    QPalette pa;
    pa.setColor(QPalette::WindowText,Qt::white);
    m_pLab[0]->setFont(ft);
    m_pLab[0]->setPalette(pa);
    m_pLab[3]->setFont(ft);
    m_pLab[3]->setPalette(pa);
    m_pLab[6]->setFont(ft);
    m_pLab[6]->setPalette(pa);

    m_pLab[0]->setText("图表");
    m_pLab[0]->setStyleSheet("background:rgb(0,205,205);"
                             "font-family:'幼圆';font-size:20px;"
                             "border:2px groove gray;border-radius:5px;padding:2px 4px;"
                             "text-align:center;");
    m_pLab[0]->setFixedWidth(/*this->width()/4*/200);

    m_pLab[1]->setText("X坐标:");
    m_pLab[1]->setStyleSheet("font-family:'幼圆';font-size:20px;");
    m_pLab[2]->setText("Y坐标:");
    m_pLab[2]->setStyleSheet("font-family:'幼圆';font-size:20px;");

    m_pCom[0]->setStyleSheet("font-family:'幼圆';font-size:20px;");
    m_pCom[1]->setStyleSheet("font-family:'幼圆';font-size:20px;");

    m_pLab[3]->setText("线性回归方程");
    m_pLab[3]->setFixedWidth(/*this->width()/4*/250);
    m_pLab[3]->setStyleSheet("background:rgb(0,205,205);"
                             "font-family:'幼圆';font-size:20px;"
                             "border:2px groove gray;border-radius:5px;padding:2px 4px;");

    m_pLab[4]->setText("Y");
    m_pLab[5]->setText("R2");  //回归的决定系数
    m_pLab[4]->setStyleSheet("font-family:'幼圆';font-size:20px;");
    m_pLab[5]->setStyleSheet("font-family:'幼圆';font-size:20px;");

    m_pLab[6]->setText("预测"+m_pCom[1]->currentText());
    m_pLab[6]->setFixedWidth(/*this->width()/4*/250);
    m_pLab[6]->setStyleSheet("background:rgb(0,205,205);"
                             "font-family:'幼圆';font-size:20px;"
                             "border:2px groove gray;border-radius:5px;padding:2px 4px;");

    m_pLab[7]->setText("请输入"+m_pCom[0]->currentText()+":");

    m_pLab[7]->setStyleSheet("font-family:'幼圆';font-size:20px;");


    m_pMybar1->addWidget(m_pLab[1]);
    m_pMybar1->addWidget(m_pCom[0]);
    m_pMybar1->addSeparator();
    m_pMybar1->addSeparator();

    m_pMybar1->addWidget(m_pLab[2]);
    m_pMybar1->addWidget(m_pCom[1]);
    m_pMybar1->addSeparator();
    m_pMybar1->addSeparator();

    m_pMybar1->addWidget(m_pHuaTu);
    m_pMybar1->addSeparator();
    m_pMybar1->addSeparator();

    m_pMybar1->addWidget(m_pNiHe);

    m_pMybar2->addWidget(m_pLab[7]);
    m_pMybar2->addWidget(m_pLin);
    m_pMybar2->addWidget(m_Yuce);

    m_pMybar3->addWidget(m_pXuce);
    m_pMybar3->addWidget(m_pStudy);



//    m_pMylay->addWidget(m_pLab[0]);
    m_pMylay->addWidget(m_pMybar1);

    m_pMylay->addWidget(m_chartView);

    m_pMylay->addWidget(m_pLab[3]);
    m_pMylay->addWidget(m_pLab[4]);
    m_pMylay->addWidget(m_pLab[5]);
    m_pMylay->addWidget(m_pLab[6]);
    m_pMylay->addWidget(m_pMybar2);
    m_pMylay->addWidget(m_pMybar3);

    connect(m_pStudy,SIGNAL(clicked(bool)),this,SLOT(slot_startStudy()));
//    connect(m_pCom[0],SIGNAL(currentIndexChanged()),this,SLOT(slot_clearPoint()));

}

void CChartView::Conbox_addItem()
{
    m_pAddPoint.clear();
    m_pCom[0]->clear();
    m_pCom[1]->clear();
    m_chart->removeAllSeries();
//    m_chart->axes(Qt::Vertical).clear();
    m_chart->hide();
    m_Yuce->setText("");

    for(int i =0; i<m_pItem.length();i++)
    {
        m_pCom[0]->addItem(m_pItem.at(i));
        m_pCom[1]->addItem(m_pItem.at(i));
    }
    m_pLab[4]->setText("Y");
    m_pLab[5]->setText("R2");  //回归的决定系数
    m_pLab[6]->setText("预测"+m_pCom[1]->currentText());
    m_pLab[7]->setText("请输入"+m_pCom[0]->currentText()+":");

}

void CChartView::createChart()
{
    m_chart = new QChart();
    m_chart->setTitle("八中人工智能课程-线性回归");
    m_chartView = new QChartView(m_chart);
    m_chartView->setRenderHint(QPainter::Antialiasing);

}

void CChartView::find_Max_Min()
{
    for(int j=0; j<TABLE_COL; j++)
    {
        QList<float> zhulei;

        for(int m = 0; m <TABLE_ROW; m++)
        {
            zhulei << ret.at(m).at(j).toFloat();
        }
        float max_ = *std::max_element(zhulei.begin(),zhulei.end());
        max_rang << max_;
        float min_ = *std::min_element(zhulei.begin(),zhulei.end());
        min_rang << min_;
        qDebug()<< "MAX" << max_ << "MIN" << min_;
    }

}

void CChartView::slot_drawPointCloud()
{
    m_chart->show();

    m_chart->removeAllSeries(); // 清空
    max_rang.clear(); min_rang.clear(); //清空量程范围
    m_chart->setAnimationOptions(QChart::SeriesAnimations);

    m_scatterSeries = new QScatterSeries();//创建散点
    QString SeriesName = m_pCom[0]->currentText() + "/"+m_pCom[1]->currentText();
    m_scatterSeries->setName(SeriesName);

    find_Max_Min();

    /*获取数据加载到散点图中*/
    for(int i = 0; i < ret.length();i++)
    {
        *m_scatterSeries << QPointF(ret.at(i).at(m_pCom[0]->currentIndex()).toFloat(),
                ret.at(i).at(m_pCom[1]->currentIndex()).toFloat());
    }

    if(!m_pAddPoint.isEmpty())
    {
        for(int i = 0; i < m_pAddPoint.length();i++)
        {
            *m_scatterSeries << m_pAddPoint.at(i);
        }
    }

    m_scatterSeries->setMarkerShape(QScatterSeries::MarkerShapeCircle);//设置散点样式
    m_scatterSeries->setMarkerSize(10);//设置散点大小
    m_scatterSeries->setColor(QColor(255, 54, 38));
    m_scatterSeries->setBorderColor(QColor(255, 54, 38));
    m_scatterSeries->setOpacity(0.4);

    m_chart->addSeries(m_scatterSeries);
    m_chart->createDefaultAxes();

    m_chart->axes(Qt::Horizontal).first()->setRange
            (min_rang.at(m_pCom[0]->currentIndex()),
             max_rang.at(m_pCom[0]->currentIndex()));
    m_chart->axes(Qt::Horizontal).first()->setTitleText(m_pCom[0]->currentText());
    m_chart->axes(Qt::Vertical).first()->setRange
            (min_rang.at(m_pCom[1]->currentIndex()),
             max_rang.at(m_pCom[1]->currentIndex()));
    m_chart->axes(Qt::Vertical).first()->setTitleText(m_pCom[1]->currentText());
    m_chart->axes(Qt::Horizontal).first()->setGridLineVisible(false);   //隐藏背景网格X轴框线

    connect(m_scatterSeries, &QScatterSeries::hovered, this, &CChartView::slot_PointHoverd);//用于鼠标移动到点上显示数值
}

void CChartView::slot_handleClickedPoint(const QPointF &point)
{

}

void CChartView::slot_PointHoverd(const QPointF &point, bool state)
{
    if (state) {
            m_valueLabel->setText(QString("%1 %2").arg( point.x()).arg(point.y()));

            QPoint curPos = mapFromGlobal(QCursor::pos());
            m_valueLabel->move(curPos.x() - m_valueLabel->width() / 2, curPos.y() - m_valueLabel->height() * 1.5);//移动数值

            m_valueLabel->show();//显示出来
            qDebug()<<curPos.x() - m_valueLabel->width() / 2<<curPos.y() - m_valueLabel->height() * 1.5<<point.x()<<point.x();
        }
        else
            m_valueLabel->hide();//进行隐藏

}


void CChartView::slot_drawNiheLine()
{
    m_chart->show();

    int num_ = ret.length();

    if(!m_pAddPoint.isEmpty())
        num_ += m_pAddPoint.length();


    if(num_ <= 0)
    {
        qDebug()<<"请导入数据或者导入数据有误";
        return;
    }
    qDebug()<<"开始拟合 点数" << num_;
    float Answer[2];
    float SSR_SSE[4];//回归平方和  残差平方和

    float data[num_][2] ;
    for (int i = 0; i < ret.length(); i ++)
    {
        data[i][0]  = ret.at(i).at(m_pCom[0]->currentIndex()).toFloat();
        data[i][1]  = ret.at(i).at(m_pCom[1]->currentIndex()).toFloat();
    }

    if(!m_pAddPoint.isEmpty())
    {
        for (int i = 0; i < m_pAddPoint.length(); i ++)
        {
            data[i+ret.length()][0]  = m_pAddPoint.at(i).x();
            data[i+ret.length()][1]  = m_pAddPoint.at(i).y();
        }
    }

    linearEquations((float*)data,num_,&Answer[0],&Answer[1],SSR_SSE);
    a_x = Answer[1]; b_y = Answer[0];
    m_pLab[4]->setText(QString("Y = %1X + %2").arg(Answer[1]).arg(Answer[0]));

    /*SST=SSR+SSE，SST(total sum of squares)为总平方和，
      SSR(regression sum of squares)为回归平方和，
      SSE(error sum of squares) 为残差平方和*/
    float SST = SSR_SSE[0]+SSR_SSE[1];
    float R2=SSR_SSE[0]/ SST;   //  SSR/SST
    R_2 = R2;
    m_pLab[5]->setText(QString("R^2 = %1 ").arg(R2));


    /******************画直线***************/
    m_chart->removeAllSeries(); // 清空
    m_chart->setAnimationOptions(QChart::SeriesAnimations);
    m_scatterSeries = new QScatterSeries();//创建散点
    m_lineSeries = new QLineSeries();//创建折线
    QString SeriesName = m_pCom[0]->currentText() + "/"+m_pCom[1]->currentText();
    m_scatterSeries->setName(SeriesName);
    m_lineSeries->setName(m_pCom[0]->currentText() + "/"+m_pCom[1]->currentText()+"回归线");

    //找出最大最小值
    find_Max_Min();
    /*获取数据加载到散点图中*/
    for(int i = 0; i < ret.length();i++)
    {
        *m_scatterSeries << QPointF(ret.at(i).at(m_pCom[0]->currentIndex()).toFloat(),
                ret.at(i).at(m_pCom[1]->currentIndex()).toFloat());
    }
    if(!m_pAddPoint.isEmpty())
    {
        for(int i = 0; i < m_pAddPoint.length();i++)
        {
            *m_scatterSeries << m_pAddPoint.at(i);
        }
    }
    m_scatterSeries->setMarkerShape(QScatterSeries::MarkerShapeCircle);//设置散点样式
    m_scatterSeries->setMarkerSize(10);//设置散点大小
    m_scatterSeries->setColor(QColor(255, 54, 38));
    m_scatterSeries->setBorderColor(QColor(255, 54, 38));
    m_scatterSeries->setOpacity(0.4);
    m_chart->addSeries(m_scatterSeries);


    m_lineSeries->setPen(QPen(Qt::lightGray,2,Qt::SolidLine));
    m_lineSeries->setColor(QColor(0 ,206, 209));


    float p_y_min = (min_rang.at(m_pCom[0]->currentIndex()))*Answer[1]+Answer[0];
    float p_y_max = (max_rang.at(m_pCom[0]->currentIndex()))*Answer[1]+Answer[0];
    qDebug()<<p_y_min<<p_y_max;


    *m_lineSeries << QPointF((min_rang.at(m_pCom[0]->currentIndex())), p_y_min)
            << QPointF((max_rang.at(m_pCom[0]->currentIndex())), p_y_max);
    m_chart->addSeries(m_lineSeries);
    m_chart->createDefaultAxes();

    m_chart->axes(Qt::Horizontal).first()->setRange
            (min_rang.at(m_pCom[0]->currentIndex()),
             max_rang.at(m_pCom[0]->currentIndex()));
    m_chart->axes(Qt::Horizontal).first()->setTitleText(m_pCom[0]->currentText());
    m_chart->axes(Qt::Vertical).first()->setRange
            (min_rang.at(m_pCom[1]->currentIndex()),
             max_rang.at(m_pCom[1]->currentIndex()));
    m_chart->axes(Qt::Vertical).first()->setTitleText(m_pCom[1]->currentText());
    m_chart->axes(Qt::Horizontal).first()->setGridLineVisible(false);   //隐藏背景网格X轴框线
    connect(m_scatterSeries, &QScatterSeries::hovered, this, &CChartView::slot_PointHoverd);//用于鼠标移动到点上显示数值

    /*改变预测标签*/


}


int CChartView::linearEquations(float * data, int rows,float* a, float* b,float* SquarePoor)
{
    int m;
    float * p,Lxx = 0.0 ,Lxy = 0.0 ,xa = 0.0 ,ya = 0.0 ;
    if (data == 0 || a == 0 || b == 0 || rows < 1 )
        return - 1 ;
    for (p = data,m = 0 ;m < rows;m ++ )
    {
    xa += * p ++ ;
    ya += * p ++ ;
    }
    xa /= rows; // X平均值
    ya /= rows; // Y平均值
    for (p = data,m = 0 ;m < rows;m ++ ,p += 2 )
    {
    Lxx += (( * p - xa) * ( * p - xa)); // Lxx=Sum((X-Xa)平方)
    Lxy += (( * p - xa) * ( * (p + 1 ) - ya)); // Lxy=Sum((X-Xa)(Y-Ya))
    }
    * b = Lxy / Lxx; // b=Lxy/Lxx
    * a = ya - * b * xa; // a=Ya-b*Xa
    if (SquarePoor == 0 )
        return 0 ;
    // 方差分析
    SquarePoor[ 0 ] = SquarePoor[ 1 ] = 0.0 ;
    for (p = data,m = 0 ;m < rows;m ++ ,p ++ )
    {
    Lxy = * a + * b * * p ++ ;
    SquarePoor[ 0 ] += ((Lxy - ya) * (Lxy - ya)); // U(回归平方和)
    SquarePoor[ 1 ] += (( * p - Lxy) * ( * p - Lxy)); // Q(剩余平方和)
    }
    SquarePoor[ 2 ] = SquarePoor[ 0 ]; // 回归方差
    SquarePoor[ 3 ] = SquarePoor[ 1 ] / (rows - 2 ); // 剩余方差
    return 0 ;
}


void CChartView::slot_drawShowTest()
{
    if(!m_pLin->text().isEmpty())
    {
        float a = m_pLin->text().toFloat();
        float res = a*a_x+b_y;
        qDebug()<<"预测结果"<<res;
//        m_Yuce->setText(QString("预测"+m_pCom[1]->currentText()+"结果 : %1").arg(res));
//        m_Yuce->show();
        QMessageBox * meg  = new QMessageBox();
        meg->setWindowTitle("预测结果");
        meg->setStyleSheet("font-family:'幼圆';font-size:20px;");
//        message->setIcon(QMessageBox::Information);
        meg->setWindowIcon(QIcon(":/new/prefix1/yuce.png"));
        meg->setText(QString("预测"+m_pCom[1]->currentText()+"结果 : %1").arg(res));
        meg->show();
    }
    else
    {
        QMessageBox::critical(NULL, "预测失败", "预测失败，请输入合理数据", QMessageBox::NoButton, QMessageBox::Close);
        return;
    }

}


void CChartView::slot_changeLable()
{
    m_pLab[6]->setText("预测"+m_pCom[1]->currentText());
    m_pLab[7]->setText("请输入"+m_pCom[0]->currentText()+":");
    m_pAddPoint.clear();
}


void CChartView::Sleep(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void CChartView::slot_startStudy()
{
    if(R_2 >= 0.500 && R_2 < 1)
    {
        QMessageBox * message  = new QMessageBox();//(QMessageBox::NoButton,"机器学习", "机器学习模拟样本数据中···");
        message->setWindowTitle("机器学习");
        message->setStyleSheet("font-family:'幼圆';font-size:20px;");
        message->setWindowIcon(QIcon(":/new/prefix1/study.png"));
        message->show();
        message->setFixedWidth(500);
        for(int time_ = 0;time_<3;time_++){
            message->setText("机器学习模拟样本数据中 ·                             ");
            Sleep(500);
            message->setText("机器学习模拟样本数据中 ·  ·                             ");
            Sleep(500);
            message->setText("机器学习模拟样本数据中 ·  ·  ·                         ");
            Sleep(450);
        }

        //y轴差值
        float l_num = (max_rang.at(m_pCom[1]->currentIndex())- min_rang.at(m_pCom[1]->currentIndex()))/8;

        //x轴差值
        float z_num = (max_rang.at(m_pCom[0]->currentIndex())-min_rang.at(m_pCom[0]->currentIndex()))/TABLE_ROW;
        for(int i = 0; i < TABLE_ROW; i++)
        {
            float x_num = min_rang.at(m_pCom[0]->currentIndex())+i*z_num;
            float y_num = 0;

            if((int)(2*l_num) == 0)
            {
                y_num = x_num*a_x+b_y + (float)(rand()%10)*0.02 - 0.01;
            }
            else
            {
                y_num = x_num*a_x+b_y + rand()%((int)(2*l_num)) - l_num;
            }

            m_pAddPoint << QPointF(x_num,y_num);

        }
        qDebug() << "机器学习完成" << z_num  <<"y轴差值" <<l_num;
//        message-> setText(QString("机器学习模拟样本数据完成！当前样本数据量为 %1 ,请重新画散点图并拟合生成新的线性回归方程。").arg(m_pAddPoint.length()+TABLE_ROW));
        message-> setText(QString("机器学习模拟样本数据完成！简单机器学习就是通过增加样本数据量来修正模型的过程,请重新画散点图并拟合生成新的线性回归方程。"));

    }
    else if(R_2 == 0)
    {
        QMessageBox::critical(NULL, "学习失败", "请拟合生成决定系数再进行机器学习···", QMessageBox::NoButton, QMessageBox::Close);
        return;
    }
    else
    {
        QMessageBox::critical(NULL, "学习失败", "决定系数R^2小于0.5或大于等于1,数据关联性不强,不支持机器学习···", QMessageBox::NoButton, QMessageBox::Close);
        return;

    }


}

void CChartView::slot_clearPoint()
{
}
